package com.uuah.server.endpoint;

import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.uuah.server.api.IUuahContext;
import com.uuah.server.api.endpoint.IEndpointURI;
import com.uuah.server.api.endpoint.IUuahEndpoint;
import com.uuah.server.api.transformer.IBaseTransformer;
import com.uuah.server.api.transport.IConnector;
import com.uuah.server.api.transport.retry.RetryPolicyTemplate;
import com.uuah.utils.ClassUtils;

/**
 * <code>UuahEndpoint</code> describes a Provider in the Uuah Server. A endpoint
 * is a grouping of an endpoint, an endpointUri and a transformer.
 *
 * <p>
 * update record:updator，update time，update content and version
 * </p>
 *
 * @author <a href="jonny_quan@hotmail.com">jonny</a>
 * @date 2009 2009-3-27 下午01:36:02
 * @version 1.0.0
 */
public abstract class AbstractEndpoint implements IUuahEndpoint {

	private static final long serialVersionUID = -1650380871293160973L;

	protected static final Logger logger = LoggerFactory
			.getLogger(AbstractEndpoint.class);

	private final IConnector connector;

	private final IEndpointURI endpointUri;

	private final IBaseTransformer requestTransformer;

	private final IBaseTransformer responseTransformer;

	private final String name;

	private Map properties = new HashMap();

	private final boolean synchronous;
	private final boolean ipFilter;

	private final String initialState;

	private final String endpointEncoding;

	private final IUuahContext uuahContext;

	protected RetryPolicyTemplate retryPolicyTemplate;

	private String endpointBuilderName;

	public AbstractEndpoint(IConnector connector, IEndpointURI endpointUri,
			IBaseTransformer requestTransformer,
			IBaseTransformer responseTransformer, String name, Map properties,
			boolean synchronous, boolean ipFilter, String initialState,
			String endpointEncoding, String endpointBuilderName,
			IUuahContext uuahContext, RetryPolicyTemplate retryPolicyTemplate) {
		this.connector = connector;
		this.endpointUri = endpointUri;
		this.requestTransformer = requestTransformer;
		this.responseTransformer = responseTransformer;
		this.name = name;
		this.properties.putAll(properties);
		this.initialState = initialState;
		this.endpointEncoding = endpointEncoding;
		this.endpointBuilderName = endpointBuilderName;
		this.uuahContext = uuahContext;
		this.retryPolicyTemplate = retryPolicyTemplate;
		this.synchronous = synchronous;
		this.ipFilter = ipFilter;
	}

	public IEndpointURI getEndpointURI() {
		return endpointUri;
	}

	public String getEncoding() {
		return endpointEncoding;
	}

	public IConnector getConnector() {
		return connector;
	}

	public String getName() {
		return name;
	}

	public IBaseTransformer getRequestTransformer() {
		return requestTransformer;
	}

	public Map getProperties() {
		return properties;
	}

	public boolean isReadOnly() {
		return true;
	}

	public String toString() {
		String sanitizedEndPointUri = null;
		URI uri = null;
		if (endpointUri != null) {
			sanitizedEndPointUri = endpointUri.toString();
			uri = endpointUri.getUri();
		}

		if (uri != null && (uri.getRawUserInfo() != null)
				&& (uri.getScheme() != null) && (uri.getHost() != null)
				&& (uri.getRawPath() != null)) {

			Pattern sanitizerPattern = Pattern.compile("(.*):.*");
			Matcher sanitizerMatcher = sanitizerPattern.matcher(uri
					.getRawUserInfo());
			if (sanitizerMatcher.matches()) {
				sanitizedEndPointUri = new StringBuffer(uri.getScheme())
						.append("://").append(sanitizerMatcher.group(1))
						.append(":<password>").append("@")
						.append(uri.getHost()).append(uri.getRawPath())
						.toString();
			}
			if (uri.getRawQuery() != null) {
				sanitizedEndPointUri = sanitizedEndPointUri + "?"
						+ uri.getRawQuery();
			}

		}

		return ClassUtils.getClassName(getClass()) + "{endpointUri="
				+ sanitizedEndPointUri + ", connector=" + connector
				+ ", requsettransformer=" + requestTransformer + ", name='"
				+ name + "'" + ", properties=" + properties + ", synchronous="
				+ synchronous + ", ipFilter=" + ipFilter + ", initialState="
				+ initialState + ", endpointEncoding=" + endpointEncoding + "}";
	}

	public String getProtocol() {
		return connector.getProtocol();
	}

	protected static boolean equal(Object a, Object b) {
		return ClassUtils.equal(a, b);
	}

	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null || getClass() != obj.getClass())
			return false;

		final AbstractEndpoint other = (AbstractEndpoint) obj;
		return equal(retryPolicyTemplate, other.retryPolicyTemplate)
				&& equal(connector, other.connector)
				&& equal(endpointEncoding, other.endpointEncoding)
				&& equal(endpointUri, other.endpointUri)
				&& equal(initialState, other.initialState)
				&& equal(name, other.name)
				&& equal(properties, other.properties)
				&& equal(responseTransformer, other.responseTransformer)
				&& synchronous == other.synchronous
				&& ipFilter == other.ipFilter
				&& equal(requestTransformer, other.requestTransformer);
	}

	public int hashCode() {
		return ClassUtils.hash(new Object[] { this.getClass(),
				retryPolicyTemplate, connector, endpointEncoding, endpointUri,
				initialState, name, properties, responseTransformer,
				requestTransformer });
	}

	public boolean isSynchronous() {
		return synchronous;
	}

	public boolean isIpFilter() {
		return ipFilter;
	}

	public String getInitialState() {
		return initialState;
	}

	public IBaseTransformer getResponseTransformer() {
		return responseTransformer;
	}

	public Object getProperty(Object key) {
		return properties.get(key);
	}

	public IUuahContext getUuahContext() {
		return uuahContext;
	}

	public RetryPolicyTemplate getRetryPolicyTemplate() {
		return retryPolicyTemplate;
	}

	public String getEndpointBuilderName() {
		return endpointBuilderName;
	}
}
